const axios = require('axios');
const { wxConfig } = require('./config.js');

/**
 * 微信小程序API封装类
 * 提供微信登录、用户信息获取等功能
 */
class WechatAPI {
    constructor() {
        this.appid = wxConfig.appid;
        this.secret = wxConfig.secret;
        this.baseURL = 'https://api.weixin.qq.com';
    }

    /**
     * 通过code获取微信openid和session_key
     * @param {string} code - 微信登录授权码
     * @returns {Promise<Object>} 返回openid和session_key
     */
    code2Session(code) {
        const url = `${this.baseURL}/sns/jscode2session`;
        const params = {
            appid: this.appid,
            secret: this.secret,
            js_code: code,
            grant_type: 'authorization_code'
        };

        return axios.get(url, { params })
            .then(response => {
                if (response.data.errcode) {
                    const error = new Error(`微信API错误: ${response.data.errcode} - ${response.data.errmsg}`);
                    error.name = 'ExternalError';
                    return Promise.reject(error);
                }

                return {
                    openid: response.data.openid,
                    session_key: response.data.session_key,
                    unionid: response.data.unionid || null
                };
            })
            .catch(error => {
                if (error.response) {
                    const apiError = new Error(`微信API请求失败: ${error.response.status} - ${error.response.statusText}`);
                    apiError.name = 'ExternalError';
                    return Promise.reject(apiError);
                }
                return Promise.reject(error);
            });
    }

    /**
     * 获取小程序全局接口调用凭据
     * @returns {Promise<string>} 返回access_token
     */
    getAccessToken() {
        const url = `${this.baseURL}/cgi-bin/token`;
        const params = {
            grant_type: 'client_credential',
            appid: this.appid,
            secret: this.secret
        };

        return axios.get(url, { params })
            .then(response => {
                if (response.data.errcode) {
                    const error = new Error(`获取access_token失败: ${response.data.errcode} - ${response.data.errmsg}`);
                    error.name = 'ExternalError';
                    return Promise.reject(error);
                }

                return response.data.access_token;
            })
            .catch(error => {
                if (error.response) {
                    const apiError = new Error(`获取access_token请求失败: ${error.response.status} - ${error.response.statusText}`);
                    apiError.name = 'ExternalError';
                    return Promise.reject(apiError);
                }
                return Promise.reject(error);
            });
    }

    /**
     * 获取小程序码
     * @param {string} path - 扫码进入的小程序页面路径
     * @param {number} width - 二维码的宽度
     * @returns {Promise<Buffer>} 返回小程序码图片buffer
     */
    getWXACode(path = 'pages/index/index', width = 430) {
        return this.getAccessToken()
            .then(accessToken => {
                const url = `${this.baseURL}/wxa/getwxacode?access_token=${accessToken}`;
                const data = {
                    path: path,
                    width: width
                };

                return axios.post(url, data, {
                    responseType: 'arraybuffer'
                });
            })
            .then(response => Buffer.from(response.data))
            .catch(error => {
                if (error.response) {
                    const apiError = new Error(`获取小程序码失败: ${error.response.status} - ${error.response.statusText}`);
                    apiError.name = 'ExternalError';
                    return Promise.reject(apiError);
                }
                return Promise.reject(error);
            });
    }

    /**
     * 获取小程序二维码
     * @param {string} path - 扫码进入的小程序页面路径
     * @param {number} width - 二维码的宽度
     * @returns {Promise<Buffer>} 返回小程序二维码图片buffer
     */
    getWXACodeUnlimit(path = 'pages/index/index', width = 430) {
        return this.getAccessToken()
            .then(accessToken => {
                const url = `${this.baseURL}/wxa/getwxacodeunlimit?access_token=${accessToken}`;
                const data = {
                    scene: 'a=1&b=2', // 场景值，可以传递参数
                    page: path,
                    width: width,
                    auto_color: false,
                    line_color: { r: 0, g: 0, b: 0 },
                    is_hyaline: false
                };

                return axios.post(url, data, {
                    responseType: 'arraybuffer'
                });
            })
            .then(response => Buffer.from(response.data))
            .catch(error => {
                if (error.response) {
                    const apiError = new Error(`获取小程序二维码失败: ${error.response.status} - ${error.response.statusText}`);
                    apiError.name = 'ExternalError';
                    return Promise.reject(apiError);
                }
                return Promise.reject(error);
            });
    }

    /**
     * 发送订阅消息
     * @param {string} openid - 用户openid
     * @param {string} templateId - 模板ID
     * @param {Object} data - 模板数据
     * @param {string} page - 跳转页面
     * @returns {Promise<Object>} 返回发送结果
     */
    sendSubscribeMessage(openid, templateId, data, page = 'pages/index/index') {
        return this.getAccessToken()
            .then(accessToken => {
                const url = `${this.baseURL}/cgi-bin/message/subscribe/send?access_token=${accessToken}`;
                const messageData = {
                    touser: openid,
                    template_id: templateId,
                    page: page,
                    data: data
                };

                return axios.post(url, messageData);
            })
            .then(response => {
                if (response.data.errcode !== 0) {
                    const error = new Error(`发送订阅消息失败: ${response.data.errcode} - ${response.data.errmsg}`);
                    error.name = 'ExternalError';
                    return Promise.reject(error);
                }

                return response.data;
            })
            .catch(error => {
                if (error.response) {
                    const apiError = new Error(`发送订阅消息请求失败: ${error.response.status} - ${error.response.statusText}`);
                    apiError.name = 'ExternalError';
                    return Promise.reject(apiError);
                }
                return Promise.reject(error);
            });
    }

    /**
     * 获取小程序用户信息（需要用户授权）
     * @param {string} sessionKey - 会话密钥
     * @param {string} encryptedData - 加密的用户数据
     * @param {string} iv - 加密算法的初始向量
     * @returns {Promise<Object>} 返回解密后的用户信息
     */
    getUserInfo(sessionKey, encryptedData, iv) {
        return new Promise((resolve, reject) => {
            const crypto = require('crypto');

            // 解密用户信息
            const sessionKeyBuffer = Buffer.from(sessionKey, 'base64');
            const encryptedDataBuffer = Buffer.from(encryptedData, 'base64');
            const ivBuffer = Buffer.from(iv, 'base64');

            let decipher;
            try {
                decipher = crypto.createDecipher('aes-128-cbc', sessionKeyBuffer);
                decipher.setAutoPadding(true);
                decipher.setAAD(Buffer.from(''));

                let decrypted = decipher.update(encryptedDataBuffer, null, 'utf8');
                decrypted += decipher.final('utf8');

                resolve(JSON.parse(decrypted));
            } catch (error) {
                const decryptError = new Error(`解密用户信息失败: ${error.message}`);
                decryptError.name = 'ExternalError';
                reject(decryptError);
            }
        });
    }

    /**
     * 检查微信API配置
     * @returns {Promise<boolean>} 返回配置是否有效
     */
    checkConfig() {
        return this.getAccessToken()
            .then(accessToken => !!accessToken)
            .catch(() => false);
    }
}

// 创建单例实例
const wechatAPI = new WechatAPI();

module.exports = wechatAPI;